Grids
This documentation is for an older version of ZK. For the latest one, please click here.
Components: grid
, columns
, column
, rows
and row
.
A grid contains components that are aligned in rows like tables. Inside a grid, you declare two things, the columns and the rows. Within the columns you define the header and the column attributes and then provide the row content.
To declare row data use the rows
component which is a child element of grid
. Inside that you should add row
components, which are used for each row. Inside the row element, you should place the content that you want inside that row. Each child is a column of the specific row.
Similarly, the columns are declared with the columns
component, which should be a child element of grid
. column
declares the common attributes of each column, such as the width and alignment, and optional headers, i.e., label and/or image.
<grid>
<columns>
<column label="Type"/>
<column label="Content"/>
</columns>
<rows>
<row>
<label value="File:"/>
<textbox width="99%"/>
</row>
<row>
<label value="Type:"/>
<hbox>
<listbox rows="1" mold="select">
<listitem label="Java Files,(*.java)"/>
<listitem label="All Files,(*.*)"/>
</listbox>
<button label="Browse..."/>
</hbox>
</row>
</rows>
</grid>
Scrollable Grid
A grid can be scrollable if you specify the height
attribute and there is not enough space to display all data.
<grid width="500px" height="130px">
<columns>
<column label="Head 1"/>
<column label="Head 2" align="center"/>
<column label="Head 3" align="right"/>
</columns>
<rows>
<row>
<listbox mold="select">
<listitem label="Faster"/>
<listitem label="Fast"/>
<listitem label="Average"/>
</listbox>
<datebox/>
<textbox rows="2"/>
</row>
<row>
<checkbox checked="true" label="Option 1"/>
<checkbox label="Option 2"/>
<radiogroup>
<radio label="Apple"/>
<radio label="Orange" checked="true"/>
<radio label="Lemon"/>
</radiogroup>
</row>
<row>
<checkbox checked="true" label="Option 1"/>
<checkbox label="Option 2"/>
<radiogroup orient="vertical">
<radio label="Apple"/>
<radio label="Orange" checked="true"/>
<radio label="Lemon"/>
</radiogroup>
</row>
</rows>
</grid>
Sizable Columns
If you allow users to resize the width of your columns, you can set the sizable
attribute of your columns as true
. Once allowed, users can resize the widths of columns by dragging the border between adjacent column
components.
<window>
<grid>
<columns id="cs" sizable="true">
<column label="AA"/>
<column label="BB"/>
<column label="CC"/>
</columns>
<rows>
<row>
<label value="AA01"/>
<label value="BB01"/>
<label value="CC01"/>
</row>
<row>
<label value="AA01"/>
<label value="BB01"/>
<label value="CC01"/>
</row>
<row>
<label value="AA01"/>
<label value="BB01"/>
<label value="CC01"/>
</row>
</rows>
</grid>
<checkbox label="sizeable" checked="true" onCheck="cs.sizeable = self.checked"/>
</window>
The onColSize Event
Once a user resizes the width, the onColSize
event is sent with an instance of ColSizeEvent. Notice that the column's width is adjusted before the onColSize
event is sent. In other words, the event serves as a notification that you can ignore. Of course, you can do whatever you want in the event listener.
Grids with Paging
There are two ways to handle large content in a grid, scrolling and paging. Scrolling is enabled by setting the height
attribute as discussed in the previous section. Paging is enabled by setting the mold
attribute to paging
. Once paging is enabled, the grid separates the content into several pages and displays one page at a time as depicted below.
<grid width="300px" mold="paging" pageSize="4">
<columns>
<column label="Left"/>
<column label="Right"/>
</columns>
<rows>
<row>
<label value="Item 1.1"/><label value="Item 1.2"/>
</row>
<row>
<label value="Item 2.1"/><label value="Item 2.2"/>
</row>
<row>
<label value="Item 3.1"/><label value="Item 3.2"/>
</row>
<row>
<label value="Item 4.1"/><label value="Item 4.2"/>
</row>
<row>
<label value="Item 5.1"/><label value="Item 5.2"/>
</row>
<row>
<label value="Item 6.1"/><label value="Item 6.2"/>
</row>
<row>
<label value="Item 7.1"/><label value="Item 7.2"/>
</row>
</rows>
</grid>
Once the paging mold is set, the grid creates an instance of the paging
component as a child of the grid and the paging component in turn handles the grid』s paging. Therefore, the number of the grid』s
children includes the paging component. Also, if you remove all children of the grid
, the paging
is also removed.
The pageSize Property
Having set the paging
mold, you can specify how many rows are visible at a time (i.e., the page size) by setting the pageSize
attribute to a numeric value. By default, it is 20.
The paginal Property
If you prefer to place the paging
component in a different location or you want to control two or more grids with the same paging
component, you can assign the paginal
attribute explicitly. Note: if it is not set explicitly, it is the same as the paging
property.
<vbox>
<paging id="pg" pageSize="4"/>
<hbox>
<grid width="300px" mold="paging" paginal="${pg}">
<columns>
<column label="Left"/><column label="Right"/>
</columns>
<rows>
<row>
<label value="Item 1.1"/><label value="Item 1.2"/>
</row>
<row>
<label value="Item 2.1"/><label value="Item 2.2"/>
</row>
<row>
<label value="Item 3.1"/><label value="Item 3.2"/>
</row>
<row>
<label value="Item 4.1"/><label value="Item 4.2"/>
</row>
<row>
<label value="Item 5.1"/><label value="Item 5.2"/>
</row>
<row>
<label value="Item 6.1"/><label value="Item 6.2"/>
</row>
<row>
<label value="Item 7.1"/><label value="Item 7.2"/>
</row>
</rows>
</grid>
<grid width="300px" mold="paging" paginal="${pg}">
<columns>
<column label="Left"/><column label="Right"/>
</columns>
<rows>
<row>
<label value="Item A.1"/><label value="Item A.2"/>
</row>
<row>
<label value="Item B.1"/><label value="Item B.2"/>
</row>
<row>
<label value="Item C.1"/><label value="Item C.2"/>
</row>
<row>
<label value="Item D.1"/><label value="Item D.2"/>
</row>
<row>
<label value="Item E.1"/><label value="Item E.2"/>
</row>
<row>
<label value="Item F.1"/><label value="Item F.2"/>
</row>
</rows>
</grid>
</hbox>
</vbox>
The paging Property
It is a read-only attribute representing the child paging
component that is created automatically. It is null if you assign external paging via the paginal
attribute. You rarely need to access this attribute as it is generally better to use the paginal
attribute.
The onPaging Event and Method
Once a user clicks the page number of the paging
component, an onPaging
event is sent the grid. It is then processed by the onPaging
method. By default, the method invalidates, i.e., redraws, the content of rows
.
If you want to implement "create-on-demand" feature, you can add a event listener to the grid for the onPaging
event. The line below demonstrates how to add an EventListener.
grid.addEventListener(org.zkoss.zul.event.ZulEvents.ON_PAGING, new MyListener());
Sorting
Grids support the direct sorting of rows. To enable ascending order sorting for a particular column, you need to assign a java.util.Comparator
instance to the sortAscending
attribute of the column. Similarly, you assign a comparator to the sortDescending
property to enable the descending order.
As illustrated below, you first implement a comparator that compares any two rows of the grid, and then assign its instances to the sortAscending
and/or sortDescending
attributes. Notice: the compare
method is passed two Row instances.
<zk>
<zscript>
class MyRowComparator implements Comparator {
public MyRowComparator(boolean ascending) {
...
}
public int compare(Object o1, Object o2) {
Row r1 = (Row)o1, r2 = (Row)o2;
....
}
}
Comparator asc = new MyRowComparator(true);
Comparator dsc = new MyRowComparator(false);
</zscript>
<grid>
<columns>
<column sortAscending="${asc}" sortDescending="${dsc}"/>
...
The sortDirection Property
The sortDirection
property controls whether to show an icon to indicate the order of a particular column. If rows are sorted before being added to the grid, you should set this property explicitly.
<column sortDirection="ascending"/>
It is then maintained automatically by the grid as long as you assign the comparators to the corresponding column.
The onSort Event
When you assign at least one comparator to a column, an onSort
event is sent to the server if user clicks on it. The column
component implements a listener to automatically sort rows based on the assigned comparator.
If you prefer to handle this manually, you can add your own listener to the column for the onSort
event. To prevent the default listener to invoking the sort
method, you have to call the stopPropagation
method for the event being received. Alternatively, you can override the sort
method, see below.
The sort Method
The sort
method is the underlying implementation of the default onSort
event listener. It is also useful if you want to sort the rows using Java code. For example, you might have to call this method after adding rows (assuming they not in the proper order).
Row row = new Row();
row.setParent(rows);
row.appendChild(...);
...
if (!"natural".column.getSortDirection())
column.sort("ascending".equals(column.getSortDirection()));
The default sorting algorithm is quick-sort (by use of the sort
method from the Components class). You can override it with your own implementation.
Note: the sort
method checks the sort direction (by calling getSortDirection
). It sorts the rows only if the sort direction is different. To enforce the sorting, do as follows.
column.setSortDirection("natural");
sort(myorder);
The above code is equivalent to the following.
sort(myorder, true);
Update: see more about sorting Multiple Field Sorting on Listbox.
Live Data
Like list boxes, grids support live data. With live data, developers are able to separate the data from the view. In other words, developers only need to provide the data by implementing the ListModel interface, rather than manipulating the grid directly. The benefits are twofold.
- It is easier to use different views to show the same set of data.
- The grid sends the data to the client only if it is visible. It saves a lot of network traffic if the amount of data is large.
There are three steps to make use of live data.
1 Prepare the data in the form of a ListModel
. ZK has a concrete implementation called SimpleListModel for representing an array of objects.
2 Implement the RowRenderer interface for rendering a row of data into the grid.
- This is optional. If it is not specified the default renderer is used to render the data into the first column.
- You can implement different renderers for representing the same data in different views.
3 Set the data in the model
attribute and, optionally, the renderer in the rowRenderer
attribute.
In the following example, we prepared a list model called strset
, assign it to a grid using the model
attribute. Then, the grid will do the rest.
<window title="Live Grid" border="normal">
<zscript>
String[] data = new String[30];
for(int j=0; j < data.length; ++j) {
data[j] = "option "+j;
}
ListModel strset = new SimpleListModel(data);
</zscript>
<grid width="100px" height="100px" model="${strset}">
<columns>
<column label="options"/>
</columns>
</grid>
</window>
Sorting with Live Data
If you allow users to sort a grid with live data, you have to implement the interface, ListModelExt, in addition to the ListModel.
class MyListModel implements ListModel, ListModelExt {
public void sort(Comparator cmpr, boolean ascending) {
//do the real sorting
//notify the grid (or listbox) that data is changed by use of ListDataEvent
}
}
When a user wants to sort the grid, the grid will invoke the sort
method of ListModelExt
to sort the data. In other words, the sorting is done by the list model, rather than the grid.
After sorting, the list model will notify the grid by invoking the onChange
method of the grid』s registered ListDataListener instances. These are registered by the addListDataListener
method. In most cases, all the data is changed, so the list model usually sends the following event:
new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, -1, -1)
Auxiliary Headers
In addition to columns, you can specify auxiliary headers with the auxhead
and auxheader
components as follows.
<grid>
<auxhead>
<auxheader label="H1'07" colspan="6"/>
<auxheader label="H2'07" colspan="6"/>
</auxhead>
<auxhead>
<auxheader label="Q1" colspan="3"/>
<auxheader label="Q2" colspan="3"/>
<auxheader label="Q3" colspan="3"/>
<auxheader label="Q4" colspan="3"/>
</auxhead>
<columns>
<column label="Jan"/><column label="Feb"/><column label="Mar"/>
<column label="Apr"/><column label="May"/><column label="Jun"/>
<column label="Jul"/><column label="Aug"/><column label="Sep"/>
<column label="Oct"/><column label="Nov"/><column label="Dec"/>
</columns>
<rows>
<row>
<label value="1,000"/><label value="1,100"/><label value="1,200"/>
<label value="1,300"/><label value="1,400"/><label value="1,500"/>
<label value="1,600"/><label value="1,700"/><label value="1,800"/>
<label value="1,900"/><label value="2,000"/><label value="2,100"/>
</row>
</rows>
</grid>
The auxiliary headers support the colspan
and rowsspan
attributes that the column header don't. However, as its』 name suggests, the auxiliary headers must be placed within a column
.
Unlike column
/columns
, which can only be used with grid
, auhead
/auxheader
can be used with grid
, listbox
and tree
.
Special Properties
The spans Property
It is a list of comma separated integers, controlling whether to span a cell over several columns. The first number in the list denotes the number of columns the first cell shall span. The second number denotes the number of columns the second cell will span and so on. If a number is omitted, 1 is assumed.
For example,
<grid>
<columns>
<column label="Left" align="left"/><column label="Center" align="center"/>
<column label="Right" align="right"/><column label="Column 4"/>
<column label="Column 5"/><column label="Column 6"/>
</columns>
<rows>
<row>
<label value="Item A.1"/><label value="Item A.2"/>
<label value="Item A.3"/><label value="Item A.4"/>
<label value="Item A.5"/><label value="Item A.6"/>
</row>
<row spans="1,2,2">
<label value="Item B.1"/><label value="Item B.2"/>
<label value="Item B.4"/><label value="Item B.6"/>
</row>
<row spans="3">
<label value="Item C.1"/><label value="Item C.4"/>
<label value="Item C.5"/><label value="Item C.6"/>
</row>
<row spans=",,2,2">
<label value="Item D.1"/><label value="Item D.2"/>
<label value="Item D.3"/><label value="Item D.5"/>
</row>
</rows>
</grid>